import globalAxios, { AxiosInstance, AxiosResponse } from "axios";
import { ElMessage, ElMessageBox } from "element-plus";
import { Configuration } from "@/api-services/configuration";
import { BaseAPI, BASE_PATH } from "@/api-services/base";
import { Session } from "./storage";
import { useUserStore } from "@/stores/modules/user";

// 如果是 Angular 项目，则取消下面注释即可
// import { environment } from './environments/environment';

/**
 * 接口服务器配置
 */
export const serveConfig = new Configuration({
  // 如果是 Angular 项目，则取消下面注释，并删除 process.env.NODE_ENV !== "production"
  // basePath: !environment.production
  basePath: import.meta.env.VITE_API_URL
});

// 错误处理
export const throwError = (message: string) => {
  throw new Error(message);
};

/**
 * axios 默认实例
 */
export const axiosInstance: AxiosInstance = globalAxios;

// 这里可以配置 axios 更多选项 =========================================

// axios 请求拦截
axiosInstance.interceptors.request.use(
  conf => {
    const userStore = useUserStore();
    const accessToken = userStore.accessToken;
    // 获取本地的 token
    if (accessToken) {
      // 将 token 添加到请求报文头中
      conf.headers!["Authorization"] = `Bearer ${accessToken}`;
    }

    return conf;
  },
  error => {
    // 处理请求错误
    if (error.request) {
      ElMessage.error(error);
    }

    // 这里编写请求错误代码

    return Promise.reject(error);
  }
);
let isUnauthorizedMessageDisplayed = false;
// axios 响应拦截
axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    // 检查并存储授权信息
    checkAndStoreAuthentication(response);
    // 处理规范化结果错误
    const serve = response.data;
    if (serve && serve.hasOwnProperty("errors") && serve.errors) {
      // 处理规范化 401 授权问题
      if (serve.errors === "401 Unauthorized") {
        clearAccessTokens();
        window.location.href = "/401"; // 显示未授权页面
      }
      throwError(
        !serve.errors ? "Request Error." : typeof serve.errors === "string" ? serve.errors : JSON.stringify(serve.errors)
      );
      return Promise.reject(new Error("Request Error."));
    }

    // 这里编写响应拦截代码 =========================================

    return response;
  },
  error => {
    // 处理响应错误
    if (error.response) {
      // 获取响应对象并解析状态码
      const res = error.response;
      const status: number = res.status;
      // 检查并存储授权信息
      checkAndStoreAuthentication(res);

      // 检查 401 权限
      if (status === 401) {
        if (!isUnauthorizedMessageDisplayed) {
          Session.clear(); // 清除浏览器全部临时缓存
          clearAccessTokens();

          ElMessageBox.alert("你登录数据已失效，请重新登录", "提示", {
            // if you want to disable its autofocus
            // autofocus: false,
            confirmButtonText: "OK",
            callback: () => {
              const userStore = useUserStore();
              userStore.clearUserStore();
              window.location.href = "/"; // 去登录页
            }
          });
          isUnauthorizedMessageDisplayed = true;
        }
        return;
      }
    }
    if (error.message.indexOf("timeout") != -1) {
      ElMessage.error("网络超时");
    } else if (error.message == "Network Error") {
      ElMessage.error("网络连接错误");
    } else {
      if (error.response.data) ElMessage.error(error.response.statusText);
      else ElMessage.error("接口路径找不到");
    }
    // 这里编写响应错误代码

    return Promise.reject(error);
  }
);
// token 键定义
const accessTokenKey = "access-token";
/**
 * 检查并存储授权信息
 * @param res 响应对象
 */
export function checkAndStoreAuthentication(res: any): void {
  // 读取响应报文头 token 信息
  const accessToken = res.headers[accessTokenKey];
  //   var refreshAccessToken = res.headers[refreshAccessTokenKey];
  // 判断是否是无效 token
  if (accessToken === "invalid_token") {
    clearAccessTokens();
  }
  // 判断是否存在刷新 token，如果存在则存储在本地
  else if (
    //refreshAccessToken &&
    accessToken &&
    accessToken !== "invalid_token"
  ) {
    const userStore = useUserStore();
    //const { accessToken } = userStore;
    //console.log(token !== accessToken);
    if (!userStore.accessToken || userStore.accessToken !== accessToken) userStore.setToken(accessToken);
    //window.localStorage.setItem(accessTokenKey, accessToken);
  }
}

// 清除 token
export const clearAccessTokens = () => {
  const userStore = useUserStore();
  userStore.clearToken();
  //window.localStorage.removeItem(accessTokenKey);
  // 这里可以添加清除更多 Key =========================================
};

/**
 * 包装 Promise 并返回 [Error, any]
 * @param promise Promise 方法
 * @param errorExt 自定义错误信息（拓展）
 * @returns [Error, any]
 */
export function feature<T, U = Error>(promise: Promise<T>, errorExt?: object): Promise<[U, undefined] | [null, T]> {
  return promise
    .then<[null, T]>((data: T) => [null, data])
    .catch<[U, undefined]>((err: U) => {
      if (errorExt) {
        const parsedError = Object.assign({}, err, errorExt);
        return [parsedError, undefined];
      }

      return [err, undefined];
    });
}

/**
 * 获取/创建服务 API 实例
 * @param apiType BaseAPI 派生类型
 * @param configuration 服务器配置对象
 * @param basePath 服务器地址
 * @param axiosObject axios 实例
 * @returns 服务API 实例
 */
export function getAPI<T extends BaseAPI>(
  apiType: new (configuration?: Configuration, basePath?: string, axiosInstance?: AxiosInstance) => T,
  configuration: Configuration = serveConfig,
  basePath: string = BASE_PATH,
  axiosObject: AxiosInstance = axiosInstance
) {
  return new apiType(configuration, basePath, axiosObject);
}

/**
 * 解密 JWT token 的信息
 * @param token jwt token 字符串
 * @returns <any>object
 */
export function decryptJWT(token: string): any {
  token = token.replace(/_/g, "/").replace(/-/g, "+");
  const json = decodeURIComponent(escape(window.atob(token.split(".")[1])));
  return JSON.parse(json);
}

/**
 * 将 JWT 时间戳转换成 Date
 * @description 主要针对 `exp`，`iat`，`nbf`
 * @param timestamp 时间戳
 * @returns Date 对象
 */
export function getJWTDate(timestamp: number): Date {
  return new Date(timestamp * 1000);
}
